
const babel = require('@babel/core')
const importModule = require('@babel/helper-module-imports')
const types = require('@babel/types')



const autoLogger = (options) => {
    const { libName } = options
    return {
        visitor: {
            Program(path, state) { // 从根节点开始 
                // state 一个存放自定义节点的容器  可以将数据存入state 遍历其他节点是取出 多个节点之前共享 
                let loggerId;
                path.traverse({ // 遍历ast
                    ImportDeclaration(path) { // 如果是导入语句
                        const { node } = path
                        if (libName === node.source.value) { // 此代码块已经被导入过此模块
                            let specifier = node.specifiers[0]
                            // let specifier = path.get('specifiers.0').node  // 两种不同的写法 等价
                            loggerId = specifier.local.name // 3中不同的导入方式 取值相同
                        }
                        path.stop()
                    }
                })

                if (!loggerId) { // 源代码未使用过此模块 
                    loggerId = importModule.addDefault(path, libName, {  // 在根节点下增加一个导入语句
                        nameHint: path.scope.generateUid(libName)
                        // 每个导入必须在当前作用域内导入 对重名场景循环对变量加_ 实现
                    }).name
                    //
                }
                state.loggerNode = types.expressionStatement(types.callExpression(types.identifier(loggerId), []))
            },
            'FunctionDeclaration|ArrowFunctionExpression|FunctionExpression|ClassMethod'(path, state) {// 为4中方式添加
                const { node } = path
                if (types.isBlockStatement(node.body)) { // 如果是一个函数体执行快
                    node.body.body.unshift(state.loggerNode) // 在函数体增加一个 函数调用语句  _logger2()
                } else { // 针对 minus 语法糖情况
                    const newBody = types.blockStatement([ // newBody =loggerNode + body 
                        state.loggerNode,
                        types.returnStatement(node.body)
                    ])
                    path.get('body').replaceWith(newBody)
                }

            },
            // FunctionDeclaration(path, state) { // state 可以取到Program state中存的数据
            // },
            // ArrowFunctionExpression(path, state) {
            // },
            // FunctionExpression(path, state) {
            // },
            // ClassMethod(path, state) {
            // }
        }
    }
}

const sourceCode = `
    function sum(a,b) {return a+b}
    const minus = (a,b)=>a-b
    const multiply = function(a,b){ return a*b}
    class Calculator{
        divide(a,b){
            return a/b
        }
    }
`

const result = babel.transform(sourceCode, {
    filename: 'sum.js',
    plugins: [autoLogger({ libName: 'logger' })] // 自动日志 
})
console.log(result.code)